﻿using System;
using System.Collections.Generic;
using System.Linq;
using KxParser.Lexer;

namespace KxParser.Parser.LR
{
    public class LrParser
    {
        private ParsingProcedureEx parsingProcedure;
        public EParserStatus Status;

        public LrParser(GrammarEx[] grammars, string [] tokenNames, TokenEx[] tokens, int lookaheadLevel)
        {
            KxParserGlobal.InputTokens = tokens;
            KxParserGlobal.LookaheadLevel = lookaheadLevel;

            var prodItem = grammars.Select(p => new ProductionItemEx(p)).ToList();

			List<string> nonTerminals = new List<string>();
			foreach (GrammarEx grammar in grammars)
			{
				if (!nonTerminals.Contains(grammar.Name))
					nonTerminals.Add(grammar.Name);
			}

            KxParserGlobal.ProductionItemsEx = prodItem.ToArray();
            KxParserGlobal.Terminals = tokenNames;
            KxParserGlobal.NonTerminals = nonTerminals.ToArray();

            Status = KxParserGlobal.IsTerminalNonterminalDuplicateNames() ? EParserStatus.DuplicateTerminals : EParserStatus.NotAnalyzed;
        }

        public bool Analyze()
        {
            try
            {
                if (Status == EParserStatus.NotAnalyzed)
                {
                    var dfa = new DfaEx();

                    ParserTableEx parserTable = new ParserTableEx(dfa.GetStates());

                    parsingProcedure = new ParsingProcedureEx(parserTable, dfa.GetStates(), KxParserGlobal.InputTokens);
                    return parsingProcedure.Parse();
                }
                return false;
            }catch(Exception exception)
            {
                throw new Exception(exception.Message);
            }
        }

        public TokenEx GetErrorToken()
        {
            return parsingProcedure.GetErrorToken();
        }
    }

    public enum EParserStatus
    {
        DuplicateTerminals,
        NotAnalyzed,
        Ok
    }
}
